#pragma once

#ifndef LHJ_CORE_PROTOCOLS_NET_PROTOCOL_V1_H__
#define LHJ_CORE_PROTOCOLS_NET_PROTOCOL_V1_H__

#include <cstdint>
#include <string>
#include <model.h>

namespace cores
{
    namespace protocols
    {
        namespace net_v1
        {
            using namespace cores::datas::models::terminal;
            using namespace std;

            class NetProtocol
            {
            public:
                NetProtocol();
                virtual ~NetProtocol();

                /**
                 * @brief 获取协议长度
                 */
                virtual int length() const;

                /**
                 * @brief 转换成字节流
                 */
                virtual int toBuffer(uint8_t *buffer, const int &size);

            private:
                uint8_t _header{0xfe};
                uint8_t _tailer{0xfd};

            protected:
                /**
                 * @brief 设置协议头
                 */
                void setHeader(const uint8_t &header);

                /**
                 * @brief 设置协议尾
                 */
                void setTailer(const uint8_t &tailer);

                /**
                 * @brief 获取协议头
                 */
                uint8_t header() const;

                /**
                 * @brief 获取协议尾
                 */
                uint8_t tailer() const;

                /**
                 * @brief CRC16位校验
                 */
                virtual uint16_t crc16(const uint8_t *buffer, const int &size);

                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size) = 0;

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const = 0;
            };

            /**
             * @brief 交易数据上报
             */
            class NoDataUpload : public NetProtocol
            {
            public:
                NoDataUpload(const std::string &stationCode, const uint64_t &timestamp);
                virtual ~NoDataUpload();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                /**
                 * @brief 站点编码
                 */
                std::string _stationCode;

                /**
                 * @brief 以毫秒计数
                 */
                uint64_t _timestamp;
            };

            /**
             * @brief 交易数据上报
             */
            class TransDataUpload : public NetProtocol
            {
            public:
                TransDataUpload(const std::string &stationCode,
                                const std::string &deptCode,
                                OilTransaction *transData,
                                const bool &is_test = false);
                virtual ~TransDataUpload();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                /**
                 * @brief 站点编号
                 */
                std::string _stationCode;

                /**
                 * @brief 区域编号
                 */
                std::string _deptCode;

                /**
                 * @brief 交易数据
                 */
                OilTransaction *_transData{nullptr};

                /**
                 * @brief 是否为测试数据
                 */
                bool _is_test;
            };

            /**
             * @brief 液位仪数据上传
             */
            class LlqDataUpload : public NetProtocol
            {
            public:
                LlqDataUpload(const std::string &stationCode,
                              const std::string &deptCode,
                              LlqDataItem *data,
                              const bool &is_test = false);
                virtual ~LlqDataUpload();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                std::string _stationCode;
                std::string _deptCode;
                LlqDataItem *_data;

                bool _is_test;
            };

            /**
             * @brief 要求更新服务服务端的答复
             */
            class AskForUpdateServiceReq : public NetProtocol
            {
            public:
                AskForUpdateServiceReq(const std::string &stationCode,
                                       const uint64_t &serviceTime,
                                       const uint8_t &errorCode);
                virtual ~AskForUpdateServiceReq();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                /**
                 * @brief 站点编号
                 */
                std::string _stationCode;

                /**
                 * @brief 服务器时间
                 */
                uint64_t _serviceTime;

                /**
                 * @brief 错误码
                 */
                uint8_t _errorCode;
            };

            /**
             * @brief 客户端请求更新配置
             */

            class AskForUpdate : public NetProtocol
            {
            public:
                AskForUpdate(const std::string &stationCode, const uint64_t &now_time);
                virtual ~AskForUpdate();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);

                /**
                 * @brief 获取子类协议部分长度
                 */
                virtual int len() const;

            private:
                std::string _stationCode;

                /**
                 * @brief 当前时间
                 */
                uint64_t _currentTime;
            };

            /**
             * @brief 更新服务接受
             */
            class UpdateServiceAccept : public AskForUpdateServiceReq
            {
            public:
                UpdateServiceAccept(const std::string &stationCode,
                                    const uint64_t &serviceTime,
                                    const uint8_t &errorCode);
                virtual ~UpdateServiceAccept();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            /**
             * @brief 告知已更新
             */
            class NotifyServiceUpdated : public AskForUpdate
            {
            public:
                NotifyServiceUpdated(const string &stationCode, const uint64_t &now_time);
                virtual ~NotifyServiceUpdated();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            /**
             * @brief 已更新应答
             */
            class UpdatedResponse : public AskForUpdateServiceReq
            {
            public:
                UpdatedResponse(const string &stationCode,
                                const uint64_t &serviceTime,
                                const uint8_t &errorCode);

                virtual ~UpdatedResponse();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            /**
             * @brief 请求上传IP
             */
            class UploadIPReq : public AskForUpdate
            {
            public:
                UploadIPReq(const string &stationCode, const uint64_t &gateTime);
                virtual ~UploadIPReq();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            /**
             * @brief 请求IP答复
             */
            class IPResponseReq : public NetProtocol
            {
            public:
                IPResponseReq(const string &stationCode,
                              const string &ip,
                              const uint16_t &port,
                              const uint64_t &serviceTime,
                              const uint8_t &errorCode);

                virtual ~IPResponseReq();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
                virtual int len() const;

            private:
                string _stationCode;
                string _ip;
                uint16_t _port;
                uint64_t _serviceTime;
                uint8_t _errorCode;
            };

            /**
             * @brief 云端调试发送
             */
            class CloundDebugSend : public AskForUpdate
            {
            public:
                CloundDebugSend(const string &stationCode, const uint64_t &gatetime);
                virtual ~CloundDebugSend();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            /**
             * @brief 云端调试应答
             */
            class CloundDebugAck : public AskForUpdateServiceReq
            {
            public:
                CloundDebugAck(const std::string &stationCode,
                               const uint64_t &serviceTime,
                               const uint8_t &errorCode);

                virtual ~CloundDebugAck();

            protected:
                /**
                 * @brief 子类将各自的内容写入数据流
                 */
                virtual int writeToBuffer(uint8_t *buffer, const int &size);
            };

            
        }
    }
}

#endif